﻿///<copyright>
///Topbot (c) http://ya.topbloger.ru 2008-2014
///</copyright>
namespace BlogsAPI.Abstract
{
    using RssToolkit.Rss;
    using Sites;
    using Interfaces;
    using System;
    using Rdf;
    using System.Collections.Generic;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Diagnostics;

    /// <summary>
    /// От этого класса настледуются все элементы и получают нужный аттрибут BlogServiceAPI
    /// </summary>
    /// <remarks>Abstract class, виртуальные функции по умолчанию должны возвращать пустоту</remarks>
    [BlogServiceAPI(Description = "От этого класса наследуются все элементы и получают нужный аттрибут BlogServiceAPI")]
    public abstract class BlogServer : WebInterface, IData
    {
        /// <summary>
        /// Конструктор
        /// </summary>
        [DebuggerStepThrough]
        protected BlogServer()
        {
            _language = new CultureInfo("en-US");
            _encoding = Encoding.UTF8;
        }

        /// <summary>
        /// Получение нормализованного имени типа объекта для вставки в БД
        /// </summary>
        public String GetBlogType()
        {
            string blogtype = "";
            if (GetType().BaseType == typeof(StandAlone))
            {
                blogtype = "StandAlone";
            }
            else
            {
                object[] attributes = GetType().GetCustomAttributes(typeof(BlogServiceAPI), false);
                if (attributes != null && attributes.Length > 0)
                {
                    blogtype = ((BlogServiceAPI)attributes[0]).IsMicroblog ? "Microblog" : GetType().Name;
                }
            }
            return blogtype;
        }

        #region Регулярные выражения

        /// <summary>
        /// Нахождение ссылки на foaf
        /// </summary>
        private static readonly Regex rFoaf = new Regex(@"<link(?:[^>]+?type\W+\w+/rdf.xml\W|[^>]+?href[^\w>]+([^>'""]+)){2}", Regexoptions);
        /// <summary>
        /// Нахождение превьюшки
        /// </summary>
        private static readonly Regex rThumbnail = new Regex(@"<meta[^>]*?(?:\Wproperty[^>]+?image[^>]+?|\scontent[^\w>]+([^""'>]+)[^>]+?){2}", Regexoptions);
        private static readonly Regex rThumbnailTwitter = new Regex(@"<meta[^>]*?(?:\Wname[^>]+?twitter:image:src[^>]+?|\scontent[^\w>]+([^""'>]+)[^>]+?){2}", Regexoptions);

        #endregion

        #region Поля нужные для пользователя

        /// <summary>
        /// Уже залогинились в систему?
        /// </summary>
        protected Boolean _isLoggedIn;

        /// <summary>
        /// Под каким аккаунтом вошли
        /// </summary>
        public UserAccount LoggedInAs { get; protected set; }

        /// <summary>
        /// Номер пользователя
        /// </summary>
        protected String _userId;

        /// <summary>
        /// Является ли службой коротких сообщений
        /// </summary>
        public Boolean IsMicroblog
        {
            get
            {
                foreach (Attribute attr in
             Attribute.GetCustomAttributes(GetType()))
                {
                    // Check for the AnimalType attribute.
                    if (attr.GetType() == typeof(BlogServiceAPI))
                        return ((BlogServiceAPI)attr).IsMicroblog;
                }
                return false;
            }
        }

        #endregion

        #region Язык системы

        /// <summary>
        /// Приватный параметр отвечающий за язык
        /// </summary>
        private CultureInfo _language;

        /// <summary>
        /// Основной язык системы
        /// </summary>
        public CultureInfo Language
        {
            get
            {
                return _language;
            }
            set
            {
                _language = value;
            }
        }

        #endregion

        #region Кодировка системы

        /// <summary>
        /// Приватный параметр отвечающий за язык
        /// </summary>
        protected Encoding _encoding;

        /// <summary>
        /// Gets or sets encoding
        /// </summary>
        protected Encoding Encoding
        {
            get
            {
                return _encoding;
            }

            set
            {
                _encoding = value;
            }
        }

        #endregion

        #region Ссылки на блог - абстрактные функции

        /// <summary>
        /// проверка, является ли передаваемый урл частью этого сервиса
        /// </summary>
        /// <param name="link">Ссылка на сервис</param>
        /// <returns>True если можно работать</returns>
        public abstract Boolean ValidateLink(String link);

        /// <summary>
        /// проверка, является ли передаваемый урл частью этого сервиса
        /// </summary>
        /// <param name="link">Ссылка на сервис</param>
        /// <param name="userName">Извлечение названия блога</param>
        /// <returns>True если можно работать</returns>
        public Boolean ValidateLink(String link, out String userName)
        {
            BlogType bt;
            return ValidateLink(link, out userName, out bt);
        }

        /// <summary>
        /// проверка, является ли передаваемый урл частью этого сервиса
        /// и извлечение названия блога, если успех
        /// </summary>
        /// <param name="link">Ссылка на сервис</param>
        /// <param name="userName">Извлечение названия блога</param>
        /// <param name="bType">Тип блога</param>
        /// <returns>True если можно работать</returns>
        public abstract Boolean ValidateLink(String link, out String userName, out BlogType bType);

        /// <summary>
        /// Получение ссылки на блог блогера
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <returns>link on blog</returns>
        [DebuggerStepThrough]
        public virtual String GetBlogLink(string userName)
        {
            return GetBlogLink(userName, BlogType.User);
        }

        /// <summary>
        /// Получение ссылки на блог блогера
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - сообщество или блог</param>
        /// <returns>link on blog</returns>
        [DebuggerStepThrough]
        public abstract String GetBlogLink(string userName, BlogType btype);

        #endregion

        #region Функционал блогплатформы - виртуальные функции

        /// <summary>
        /// Умеем ли мы строить рейтингования для данной платформы
        /// </summary>
        public virtual bool HasRating
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Для некоторых блогплатформ можно унифицировать ссылки
        /// Убрать приставку данных из GA и hashtag
        /// </summary>
        /// <param name="link">ссылка на видео</param>
        /// <returns></returns>
        public virtual String ToCanonicalLink(string link)
        {
            return Common.ToCanonicalLink(link);
        }

        /// <summary>
        /// Формирование HTML кода для отображения имени пользователя
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="bt">Тип блога - сообщество или блог</param>
        /// <returns>HTML</returns>
        public virtual String GetUsernameHtml(string userName, BlogType bt)
        {
            return String.Format("<b><a href=\"{1}\">{0}</a></b>",
                userName, GetBlogLink(userName, bt));
        }

        /// <summary>
        /// Формирование HTML кода для отображения имени пользователя НА САМОМ ЖЕ СЕРВЕРЕ
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="bt">Тип блога - сообщество или блог</param>
        /// <returns>HTML</returns>
        /// <remarks>especially for lj-user</remarks>
        public virtual String GetUsernameHtmlSelf(string userName, BlogType bt)
        {
            return GetUsernameHtml(userName, bt);
        }

        /// <summary>
        /// залогинивание на сайт
        /// нужно для проверки достоверности логина-пароля
        /// </summary>
        /// <param name="user">User's accaunt</param>
        /// <returns>True if success</returns>
        public virtual bool LogInto(UserAccount user)
        {
            return false;
        }

        /// <summary>
        /// Запись строчки в отладку
        /// </summary>
        /// <param name="sText">Information to be logged into debug</param>
        public virtual void Log(string sText)
        {
            Debug.WriteLine(sText);
        }


        /// <summary>
        /// Сколько комментариев у поста 
        /// c помощью Яндекса
        /// </summary>
        /// <param name="bp">Важна только ссылка на пост</param>
        /// <returns>-1 - нет в индексе или ошибка</returns>
        public virtual int HowManyComments(BlogPost bp)
        {
            return 0;
            //return bp.Comments;//так нельзя из-за возможности зацикливаний
        }

        /// <summary>
        /// Сколько ссылок на пост
        /// c помощью Яндекса
        /// </summary>
        /// <param name="bp">Важна только ссылка на пост</param>
        /// <returns>-1 - нет в индексе или ошибка</returns>
        public virtual int HowManyLinks(BlogPost bp)
        {
            return 0;
            //return bp.Links;//так нельзя из-за возможности зацикливаний
        }

        /// <summary>
        /// Извлечение картинки пользователя
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <remarks>необязательная для реализации функция</remarks>
        public string ExtractAvatar(string userName)
        {
            return ExtractAvatar(userName, BlogType.User);
        }


        /// <summary>
        /// Извлечение картинки пользователя
        /// </summary>
        /// <param name="userName">имя блогера</param>
        /// <param name="btype">тип блога</param>
        /// <returns>Прямая ссылка на картинку</returns>
        public virtual string ExtractAvatar(string userName, BlogType btype)
        {
            return null;
        }

        /// <summary>
        /// Размещение комментария к записи в блоге по умолчанию
        /// </summary>
        /// <param name="user">Аккаунт Блогера</param>
        /// <param name="cp">пост для блога</param>
        /// <returns></returns>
        public virtual PostResult MakeComment(UserAccount user, CommentPost cp)
        {
            return new PostResult { Error = new NotImplementedException() };
        }

        /// <summary>
        /// Обрабатываем пост в соответствии с требованиями блогохостинга
        /// перед его публикацией куда-нить.
        /// </summary>
        /// <param name="bp"></param>
        /// <returns></returns>
        public virtual BlogPost PreparePost(BlogPost bp)
        {
            if (!String.IsNullOrEmpty(bp.Body) && bp.Body.Length > 40000)
            {
                bp.Body = bp.Body.Substring(0, 40000);//обрезаем на тип MEDIUMTEXT
            }
            return bp;
        }

        /// <summary>
        /// Размещение записи в блоге по умолчанию
        /// </summary>
        /// <param name="user">Аккаунт Блогера</param>
        /// <param name="bp">пост для блога</param>
        /// <returns></returns>
        public virtual PostResult MakePost(UserAccount user, BlogPost bp)
        {
            return new PostResult { Error = new NotImplementedException() };
        }

        /// <summary>
        /// Редактирование записи в блоге по умолчанию
        /// </summary>
        /// <param name="user">Аккаунт Блогера</param>
        /// <param name="bpOld">старый пост</param>
        /// <param name="bpNew">новый пост</param>
        /// <returns></returns>
        public virtual PostResult EditPost(UserAccount user, BlogPost bpOld, BlogPost bpNew)
        {
            return new PostResult { Error = new NotImplementedException() };
        }

        /// <summary>
        /// Функция подсчета числа френдов для произвольного аккаунта
        /// </summary>
        /// <param name="username">Имя пользователя или сообщества</param>
        /// <param name="bt">Тип блога</param>
        /// <returns>
        /// Вернем беззнаковый 32 битный int от 0 до 4млн+.
        /// Если не удалось определить френдов или ошибка, то возвращаем NULL.
        /// </returns>
        public virtual uint? HowManyReaders(String username, BlogType bt)
        {
            return null;
        }

        #endregion

        #region Функционал редактирования друзей

        /// <summary>
        /// Определяем сколько френдов из списка есть в наших друзьях.
        /// Для сообщества - сколько людей из списка могут писать в сообщество
        /// </summary>
        /// <param name="userName">имя блога или сообщества</param>
        /// <param name="bt">Блог или Сообщество</param>
        /// <param name="friends">список друзей</param>
        /// <returns>Список тех, что читает блог или является членами сообщества</returns>
        public virtual List<string> IsFriended(String userName, BlogType bt, params string[] friends)
        {
            List<string> myfriends = new List<string>(0);
            try
            {
                List<String> temp = new List<string>(friends);
                //для начала разберем файл фоаф для этого пользователя.
                RdfDocument foaf = ParseFoaf(userName, bt);
                Array persons = foaf.Who.Knows;
                if (foaf.Who.GetType() == typeof(FoafGroup))
                {
                    persons = ((FoafGroup)foaf.Who).Members;
                }
                if (persons != null)
                {
                    foreach (FoafKnow person in persons)
                    {
                        if (temp.Contains(person.Person.Nick.ToLower())
                            || temp.Contains(person.Person.Name.ToLower())
                            || !String.IsNullOrEmpty(temp.Find(
                                                         delegate(String item)
                                                         {
                                                             return
                                                                 person.Person.Weblog.Resource.ToLower().Contains(
                                                                     item.ToLower());
                                                         }
                                                         )))
                        {
                            if (!myfriends.Contains(person.Person.Name))
                            {
                                myfriends.Add(person.Person.Name); //фактически номер в базе данных
                            }
                        }
                    }
                }
            }
            catch (Exception e1)
            {
                Log("IsFriended: " + e1.Message);
            }
            return myfriends;
        }

        /// <summary>
        /// Интерфейс по добавлению френдов
        /// </summary>
        /// <param name="who">Имя аккаунта для которого меняем френдов</param>
        /// <param name="friends">Набор имен аккаунтов для френдования</param>
        /// <returns>NULL, если все хорошо, иначе ошибку ввиде Exception</returns>
        public virtual List<String> AddFriends(UserAccount who, params string[] friends)
        {
            return null;
        }


        /// <summary>
        /// Интерфейс по удалению френдов
        /// </summary>
        /// <param name="who">Имя аккаунта для которого меняем френдов</param>
        /// <param name="friends">Набор имен аккаунтов для френдования</param>
        /// <returns>NULL, если все хорошо, иначе ошибку ввиде Exception</returns>
        public virtual List<String> DelFriends(UserAccount who, params string[] friends)
        {
            return null;
        }

        #endregion

        #region interface IData Функционал экспорта данных

        /// <summary>
        /// Получение ссылки на rss-блогера 
        /// По умолчанию, грузим блог и извлекаем ссылку
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public virtual string GetRssLink(string userName)
        {
            return GetRssLink(userName, BlogType.User);
        }

        /// <summary>
        /// Получение ссылки на rss-блогера 
        /// По умолчанию, грузим блог и извлекаем ссылку
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - сообщество или блог</param>
        /// <returns>Link on RSS feed</returns>
        public virtual string GetRssLink(string userName, BlogType btype)
        {
            return Common.GetRSS(GetBlogLink(userName, btype));
        }

        /// <summary>
        /// Получение ссылки на Foaf-блогера
        /// По умолчанию, грузим блог и извлекаем ссылку
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - сообщество или блог</param>
        /// <returns>Link on Foaf feed</returns>
        /// <remarks><link rel="meta" type="application/rdf+xml" title="FOAF"
        /// href="http://username.livejournal.com/data/foaf" /></remarks>
        public virtual string GetFoafLink(string userName, BlogType btype)
        {
            //открываем страничку и ищем тама link="FOAF"
            string sFoafLink = "";
            try
            {
                //string result = MakeRequest2(GetBlogLink(userName, btype)).Content.ReadAsStringAsync().Result;
                HttpWebRequest myHttpWebRequest = MakeRequest(GetBlogLink(userName, btype));
                myHttpWebRequest.Method = "GET";
                myHttpWebRequest.Referer = GetBlogLink(userName);
                ////
                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                //теперь парсим ответ
                if (String.IsNullOrEmpty(result))
                {
                    throw new Exception("Получен пустой ответ.");
                }
                
                Match m = rFoaf.Match(result);
                if (m.Success)
                {
                    sFoafLink = m.Groups[1].ToString().Trim('/');
                }
            }
            catch (Exception e1)
            {
                Log("GetFoafLink: " + e1.Message);
            }
            return sFoafLink;
        }

        /// <summary>
        /// Получение одного поста просто по ссылке
        /// </summary>
        /// <param name="linkOnPost">ссылка на пост</param>
        /// <remarks>делает разбор ссылки</remarks>
        public virtual BlogPost GetOnePost(string linkOnPost)
        {
            BlogPost bpRet = null;
            string uname;
            BlogType bt;
            var server = Common.GetBlogServiceByLink(Common.FixHttp(linkOnPost),
                out uname, out bt);
            if (server != null)
            {
                bpRet = server.GetOnePost(linkOnPost, uname, bt);
            }
            return bpRet;
        }

        /// <summary>
        /// Получение одного поста по ссылке на него и данных о пользователе
        /// </summary>
        /// <param name="linkOnPost">ссылка на пост</param>
        /// <param name="userName">имя пользователя</param>
        /// <param name="btype">тип блогплатформы</param>
        /// <remarks>Может генерить исключения</remarks>
        public virtual BlogPost GetOnePost(string linkOnPost, string userName, BlogType btype)
        {
            BlogPost bpRet = null;
            Uri rsslink;
            if (Uri.TryCreate(this.GetType() == typeof(StandAlone) ?
                Common.GetRSS(linkOnPost) : //если у нас StandAlone blog, то ищем RSS на самой странице поста, а не на главной
                GetRssLink(userName, btype), UriKind.Absolute, out rsslink))
            {
                //определили сервер поста
                RssDocument rssDoc = RssDocument.Load(rsslink, false);//w/o cache
                bpRet = GetOnePost(linkOnPost, rssDoc, userName);
            }
            return bpRet;
        }

        /// <summary>
        /// Получение одного поста
        /// </summary>
        /// <param name="rssDoc"></param>
        /// <returns></returns>
        public virtual BlogPost GetOnePost(string linkOnPost, RssDocument rssDoc, string username = "")
        {
            BlogPost bpRet = null;
            if (rssDoc != null && rssDoc.Channel != null)
            {
                if (GetType() == typeof(Blogspot))
                {
                    linkOnPost = linkOnPost.Replace("blogspot.ru/", "blogspot.com/");//всегда работаем с доменом .com
                }
                foreach (RssItemYandex item in rssDoc.Channel.Items)
                {
                    var linkOnItem = Common.DelHttp(item.Link.ToLower());
                    //если ссылка на пост совпадает, то
                    if (linkOnPost.ToLower().Contains(linkOnItem)
                        || (!String.IsNullOrEmpty(item.Comments) && item.Comments.ToLower().Contains(linkOnPost.ToLower()))
                        || (item.Guid != null && String.Compare(item.Guid.Text, linkOnPost, StringComparison.InvariantCultureIgnoreCase)==0)
                        || ((GetType()==typeof(Medium) || GetType() == typeof(Blogspot)) && linkOnPost.ToLower().Contains(linkOnItem.Split('?','#')[0]))//надо обрезать параметры
                        )
                    {
                        //создаем объект и заполняем его
                        bpRet = new BlogPost(new Uri(Common.FixHttp(item.Link)))//вставляем ссылку на пост не ту, что передали, а что реальная
                        {
                            Body = item.Description??String.Empty,
                            Subject = item.Title,
                            Existance = true,
                            Published = item.PubDateParsed
                        };
                        //если есть контент, которого нет в посте, но он есть в аттачменте
                        if (item.MediaThumbnail != null && 
                            !String.IsNullOrEmpty(item.MediaThumbnail.url) &&
                            !bpRet.Body.Contains(item.MediaThumbnail.url) 
                            //&& (item.MediaContent == null || 
                            //String.IsNullOrEmpty(item.MediaContent.url) || !bpRet.Body.Contains(item.MediaContent.url))
                            )
                        {
                            if (!linkOnPost.Contains("/plus.google.com"))//дело в том, что для гугла на уровне формирования RSS уже вставили картинку в текст
                            {
                                bpRet.Body += String.Format(" <a href='{0}'><img alt='{1}' src='{2}'></a>",
                                    item.MediaContent != null && !String.IsNullOrEmpty(item.MediaContent.url)
                                        ? item.MediaContent.url
                                        : item.MediaThumbnail.url,
                                    item.MediaThumbnail.type,
                                    item.MediaThumbnail.url);
                            }
                            //предпросмотр если есть
                            bpRet.Attributes.Add(new PostAttribute(PostParams.MediaThumbnail, item.MediaThumbnail));
                        }
                        bpRet.Attributes.Add(new PostAttribute(PostParams.Date, item.PubDate));
                        string tags = String.Empty;
                        if (item.Categories != null)
                        {
                            foreach (RssCategory cat in item.Categories)
                            {
                                if (!tags.Contains(cat.Text + ","))
                                {
                                    tags += cat.Text + ",";
                                }
                            }
                            tags = tags.TrimEnd(',');
                            bpRet.Attributes.Add(new PostAttribute(PostParams.Tags, tags));
                        }
                        //найдено число комментариев(!)
                        if (item.ReplyCount > 0 || GetType() == typeof(Livejournal))
                        {
                            bpRet.Comments = item.ReplyCount;
                        }
                        //в случае ЖЖ и сообществ нужно в SpecialParam добавить имя блогера, тогда это будет постом в сообщество
                        if (GetType() == typeof(Livejournal) && rssDoc.Channel.JournalType.ToLower().Contains("community"))
                        {
                            bpRet.SpecialParam = username;
                        }
                        break;
                    }
                }
            }
            return bpRet;
        }

        /// <summary>
        /// Разбор FOAF файла для конкретного пользователя нашей системы
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - сообщество или блог</param>
        /// <returns></returns>
        public RdfDocument ParseFoaf(String userName, BlogType btype)
        {
            Uri foaflink;
            if (Uri.TryCreate(GetFoafLink(userName, btype), UriKind.Absolute, out foaflink))
            {
                return RdfDocument.Load(foaflink, false);
            }
            return null;
        }

        /// <summary>
        /// Определяем русский ли блог или нет по RSS
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="pers">процент русских сообщений минимальный</param>
        /// <returns>TRUE для русских, FALSE для нерусских, NULL - если ошибка</returns>
        public virtual Boolean? IsRussian(String userName, double pers = 0.7)
        {
            Boolean? bRet = null;
            Uri linktorss;
            if (Uri.TryCreate(GetRssLink(userName),UriKind.Absolute,out linktorss))
            {
                try
                {
                    RssDocument rss = RssDocument.Load(linktorss);
                    if (rss != null && rss.Channel != null && rss.Channel.Items.Count > 0)
                    {
                        bRet = Common.IsRussian(rss, pers);
                    }else//нету канала или нету постов
                    {
                        bRet = false;//точно нерусский
                    }
                }catch(Exception e1)
                {
                    //например неправильно сформированный RSS
                    Debug.WriteLine(e1.Message);
                }
            }
            //если текст не русский, то удаляем из общего потока
            return bRet;
        }

        
        /// <summary>
        /// Превьюшка сайта. У многих сайтов есть картинка для предпросмотра
        /// </summary>
        /// <param name="expandedUrl"></param>
        /// <returns></returns>
        protected string GetOGPreviewImage(string expandedUrl)
        {
            try
            {
                Uri linkto;
                if (Uri.TryCreate(expandedUrl, UriKind.Absolute, out linkto))
                {
                    Match m = YouTube.rYoutube.Match(expandedUrl);
                    if (m.Success)
                    {
                        //Youtube Link(!) будем экономить на запросах во вне
                        var videoCode = m.Groups[2].Value;
                        //http://i.ytimg.com/vi/HkKT3CnFkFY/default.jpg
                        return String.Format("http://i.ytimg.com/vi/{0}/default.jpg", videoCode);
                    }
                    else
                    {
                        var req = Common.MakeRequest(linkto.OriginalString);
                        using (var resp = req.GetResponse())
                        {
                            var data = new StreamReader(resp.GetResponseStream()).ReadToEnd();
                            m = (linkto.Host.Contains("twimg.com") ? rThumbnailTwitter : rThumbnail).Match(data);
                            //спец.код для твиттер-видео
                            if (m.Success)
                            {
                                Uri ogpreview;
                                if (Uri.TryCreate(m.Groups[1].Value, UriKind.Absolute, out ogpreview))
                                {
                                    //абсолютная ссылка
                                    return ogpreview.OriginalString; //
                                }
                                else
                                {
                                    //относительная ссылка
                                    return linkto.Scheme + "://" + linkto.Host + "/" + m.Groups[1].Value;
                                }
                            }
                        }
                    }
                }
            }catch(Exception e1)
            {
                Debug.Write(e1);   
            }
            return null;
        }

        #endregion

        #region Функционал отвечающий за OpenIDServer

        /// <summary>
        /// проверка является ли запрос - запросом openID авторизации
        /// </summary>
        /// <param name="url">ссылка запроса</param>
        public virtual Boolean IsOpenIDRequest(string url)
        {
            return false;
        }

        /// <summary>
        /// Передача стороннему сервису подтверждения о том, что в этом сайте мы залогинены
        /// </summary>
        /// <param name="url">ссылка запроса</param>
        /// <returns>Ссылка для возвращения в сторонний сервис</returns>
        protected string GrantOpenID(string url)
        {
            return GrantOpenID(url, LoggedInAs);//если уже залогинились
        }

        /// <summary>
        /// Передача стороннему сервису подтверждения о том, что в этом сайте мы залогинены
        /// </summary>
        /// <param name="url">ссылка запроса</param>
        /// <param name="user">аккаунт под которым логинимся</param>
        /// <returns>Ссылка для возвращения в сторонний сервис</returns>
        public virtual string GrantOpenID(string url, UserAccount user)
        {
            if (!IsOpenIDRequest(url)) return null;
            return null;
        }

        #endregion

    }
}
